home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-11-02 | 36.3 KB | 1,303 lines |
- Newsgroups: comp.sources.misc
- subject: v08i105: Make Version 1.5 (Part 2 of 3)
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Reply-To: greggy@etude.UUCP (Greg Yachuk)
-
- Posting-number: Volume 8, Issue 105
- Submitted-by: greggy@etude.UUCP (Greg Yachuk)
- Archive-name: make.gy/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 3)."
- # Contents: make.doc parse.c
- # Wrapped by greggy@etude on Mon Oct 30 19:10:08 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'make.doc' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'make.doc'\"
- else
- echo shar: Extracting \"'make.doc'\" \(17010 characters\)
- sed "s/^X//" >'make.doc' <<'END_OF_FILE'
- XNAME
- X make - maintain, update, and reconstruct groups of programs
- X
- XSYNOPSIS
- X make [-f makefile] [-dDeiknqrsSt] [target...] [macro=value ...]
- X
- XDESCRIPTION
- X MAKE takes a file of dependencies (a 'makefile') and decides what
- X commands have to be executed to bring the files up to date. These
- X commands are either executed directly from MAKE or written to the
- X standard output without executing them.
- X
- X If no makefile is specified with a -f option, MAKE reads a file
- X named `makefile', if it exists.
- X
- X If no target is specified on the command line, MAKE uses the first
- X target defined in the first makefile.
- X
- XOPTIONS
- X -f makefile
- X Use the description file `makefile'. A - as the makefile
- X argument denotes the standard input.
- X
- X -d Display the reasons why MAKE chooses to rebuild a target. All
- X dependencies which are newer are displayed
- X
- X -dd Display the dependency checks in more detail. Dependencies
- X which are older are displayed, as well as newer.
- X
- X -D Display the text of the makefiles as read in.
- X
- X -DD Display the text of the makefiles and `default.mk'.
- X
- X -e Let environment variables override macro definitions from
- X makefiles. Normally, makefile macros override environment
- X variables. Command line macro definitions always override both
- X environment variables and makefile macros definitions.
- X
- X -i Ignore error codes returned by commands. This is equivalent to
- X the special target .IGNORE:.
- X
- X -k When a nonzero error status is returned by a command, abandon
- X work on the current target, but continue with other branches
- X that do not depend on this target.
- X
- X -n No execution mode. Print commands, but do not execute them.
- X Even lines beginning with an @ are printed. However, if a
- X command line is an invocation of MAKE, that line is always
- X executed.
- X
- X -q Question mode. MAKE returns a zero or non-zero status code,
- X depending on whether or not the target file is up to date.
- X
- X -r Do not read in the default file `default.mk'.
- X
- X -s Silent mode. Do not print command lines before executing them.
- X This is equivalent to the special target .SILENT:.
- X
- X -S Undo the effect of the -k option. Stop processing when a
- X non-zero exit status is returned by a command.
- X
- X -t Touch the target files, bringing them up to date, rather than
- X performing the rules to reconstruct them.
- X
- X macro=value
- X Macro definition. This definition remains fixed for the MAKE
- X invocation. It overrides any regular definitions for the
- X specified macro within the makefiles and from the environment.
- X It is inherited by subordinate MAKE's but act as an environment
- X variable for these. That is, depending on the -e setting, it
- X may be overridden by a makefile definition.
- X
- XUSAGE
- X Makefiles
- X The first makefile read is `default.mk', which can be located any-
- X where along the PATH. It typically contains predefined macros and
- X implicit rules. For non-DOS systems (e.g. Unix), it is searched
- X for in the current directory, then in the users home directory, and
- X finally along the PATH.
- X
- X The default name of the makefile is `makefile' in the current
- X directory. If this file is not found on a non-DOS system, the file
- X `Makefile' is then used as the default. Alternate makefiles can be
- X specified using one or more '-f' options on the command line.
- X Multiple '-f's act as the concatenation of all the makefiles in a
- X left-to-right order.
- X
- X The makefile(s) may contain a mixture of comment lines, macro
- X definitions, include lines, and target lines. Lines may be
- X continued across input lines by escaping the NEWLINE with a
- X backslash (\).
- X
- X Anything after a "#" is considered to be a comment, and is stripped
- X from the line, including spaces immediately before the "#.
- X Completely blank lines are ignored.
- X
- X An include line is used to include the text of another makefile.
- X It consists of the word "include" left justified, followed by
- X spaces, and followed by the name of the file that is to be included
- X at this line. Include files may be nested.
- X
- X Macros
- X Macros have the form `WORD = text and more text'. The WORD need
- X not be uppercase, but this is an accepted standard. Later lines
- X which contain $(WORD) or ${WORD} will have this replaced by `text
- X and more text'. If the macro name is a single character, the
- X parentheses are optional. Note that the expansion is done
- X recursively, so the body of a macro may contain other macro
- X invocations.
- X
- X e.g. FLINTSTONES = wilma and fred
- X RUBBLES = barney and betty
- X BEDROCK = $(FLINTSTONES) and $(RUBBLES)
- X
- X `$(BEDROCK)' becomes `wilma and fred and barney and betty'
- X
- X Also note that whitespace around the equal sign is not relevant
- X when defining a macro. The following four macro definitions are
- X all equivalent:
- X
- X MACRO = body
- X MACRO= body
- X MACRO =body
- X MACRO=body
- X
- X Macros may be added to by using the `+=' notation. Thus
- X
- X FLINTSTONES += and pebbles and dino
- X
- X would be (given the examples above) the same as
- X
- X FLINTSTONES = wilma and fred and pebbles and dino
- X
- X Special Macros
- X MAKE
- X This normally has the value "make". Any line which invokes
- X MAKE temporarily overrides the -n option, just for the duration
- X of the one line. This allows nested invocations of MAKE to be
- X tested with the -n option.
- X
- X MAKEFLAGS
- X This macro has the set of options provided to MAKE as its
- X value. If this is set as an environment variable, the set of
- X options is processed before any command line options. This
- X macro may be explicitly passed to nested MAKEs, but it is also
- X available to these invocations as an environment variable. The
- X -f and -d flags are not recorded in this macro.
- X
- X SUFFIXES
- X This contains the default list of suffixes supplied to the
- X special target .SUFFIXES:. It is not sufficient to simply
- X change this macro in order to change the .SUFFIXES: list. That
- X target must be specified in your makefile.
- X
- X There are several dynamically maintained macros that are useful as
- X abbreviations within rules. It is best not to define them
- X explicitly.
- X
- X $* The basename of the current target.
- X
- X $< The name of the current dependency file.
- X
- X $@ The name of the current target.
- X
- X The $< and $* macros are normally used for implicit rules. They
- X may be unreliable when used within explicit target command lines.
- X These may be suffixed with D and F, to specify the Directory and
- X Filename components (e.g. ${*D}, ${@F}). If there is no directory
- X in the name, "." is supplied.
- X
- X Targets
- X A target entry in the makefile has the following format:
- X
- X target ... : [dependency ...] [; rule]
- X [rule]
- X ...
- X
- X Any line which does not have leading whitespace (other than macro
- X definitions) is a `target' line. Target lines consist of one or
- X more filenames (or macros which expand into same) called targets,
- X followed by a colon (:). The ':' is followed by a list of
- X dependent files. The dependency list may be terminated with a
- X semicolon (;) which may be followed by a rule or shell command.
- X
- X Special allowance is made on MSDOS for the colons which are needed
- X to specify files on other drives, so for example, the following
- X will work as intended:
- X
- X c:foo.bar : a:fee.ber
- X
- X If a target is named in more than one target line, the dependencies
- X and rules are added to form the target's complete dependency list
- X and rule list.
- X
- X The dependents are ones from which a target is constructed. They
- X in turn may be targets of other dependents. In general, for a
- X particular target file, each of its dependent files is `made', to
- X make sure that each is up to date with respect to it's dependents.
- X
- X The modification time of the target is compared to the modification
- X times of each dependent file. If the target is older, one or more
- X of the dependents have changed, so the target must be constructed.
- X Of course, this checking is done recursively, so that all
- X dependents of dependents of dependents of ... are up to date.
- X
- X To reconstruct a target, MAKE expands macros, strips off initial
- X whitespace, and either executes the rules directly, or passes each
- X to a shell or COMMAND.COM for execution.
- X
- X For target lines, macros are expanded on input. All other lines
- X have macro expansion delayed until absolutely required.
- X
- X Special Targets
- X .DEFAULT:
- X The rule for this target is used to process a target when there
- X is no other entry for it, and no implicit rule for building it.
- X MAKE ignores all dependencies for this target.
- X
- X .DONE:
- X This target and its dependencies are processed after all other
- X targets are built.
- X
- X .IGNORE:
- X Non-zero error codes returned from commands are ignored.
- X Encountering this in a makefile is the same as specifying -i on
- X the command line.
- X
- X .INIT:
- X This target and its dependencies are processed before any other
- X targets are processed.
- X
- X .SILENT:
- X Commands are not echoed before executing them. Encountering
- X this in a makefile is the same as specifying -s on the command
- X line.
- X
- X .SUFFIXES:
- X The suffixes list for selecting implicit rules. Specifying
- X this target with dependents adds these to the end of the
- X suffixes list. Specifying it with no dependents clears the
- X list. In order to add your own dependents to the head of the
- X list, you could enter:
- X
- X .SUFFIXES:
- X .SUFFIXES: .abc $(SUFFIXES)
- X
- X Rules
- X A line in a makefile that starts with a TAB or SPACE is a shell
- X line or rule. This line is associated with the most recently
- X preceding dependency line. A sequence of these may be associated
- X with a single dependency line. When a target is out of date with
- X respect to a dependent, the sequence of commands is executed.
- X Shell lines may have any combination of the following characters to
- X the left of the command:
- X
- X @ will not echo the command line, except if -n is used.
- X
- X - MAKE will ignore the exit code of the command, i.e. the
- X ERRORLEVEL of MSDOS. Without this, MAKE terminates when a
- X nonzero exit code is returned.
- X
- X + MAKE will use a shell or COMMAND.COM to execute the command.
- X
- X If the '+' is not attached to a shell line, but the command is a
- X DOS command or if redirection is used (<, |, >), the shell line is
- X passed to COMMAND.COM anyway. For Unix, redirection and backquote
- X (`) force the use of a shell.
- X
- X Implicit Rules
- X Implicit rules are intimately tied to the .SUFFIXES: special
- X target. Each entry in the .SUFFIXES defines an extension to a
- X filename which may be used to build another file. The implicit
- X rules then define how to actually build one file from another.
- X These files are related, in that they must share a common basename,
- X but have different extensions.
- X
- X If a file that is being made does not have an explicit target line,
- X an implicit rule is looked for. Each entry in the .SUFFIXES: list
- X is combined with the extension of the target, to get the name of an
- X implicit target. If this target exists, it gives the rules used to
- X transform a file with the dependent extension to the target file.
- X Any dependents of the implicit target are ignored.
- X
- X In the following example, the .SUFFIXES: list is .c .y .l, and the
- X target file is fred.o which does not have a target line. An
- X implicit rule target `.c.o' is constructed and searched for. If it
- X does not exist, the next suffix is tried. If the implicit rule
- X target does exist, MAKE looks for a file `fred.c'. If this file
- X does not exist, the next extension is tried. If `fred.c' does
- X exist, then the associated rules are executed to create fred.o from
- X fred.c, presumably invoking the C compiler.
- X
- X If the next extension must be tried, MAKE reiterates the above with
- X target `.y.o' and a file named `fred.y', and potentially with
- X `.l.o' and `fred.l'.
- X
- X If a file that is being made has an explicit target, but no rules,
- X a similar search is made for implicit rules. Each entry in the
- X .SUFFIXES: list is combined with the extension of the target, to
- X get the name of an implicit target. If such a target exists, then
- X the list of dependents is searched for a file with the correct
- X extension, and the implicit rules are invoked to create the target.
- X
- XEXAMPLES
- X This makefile says that pgm.exe depends on two files a.obj and
- X b.obj, and that they in turn depend on their corresponding source
- X files (a.c and b.c) along with the common file incl.h.
- X
- X pgm.exe: a.obj b.obj
- X $(CC) a.obj b.obj -o $@
- X
- X a.obj: incl.h a.c
- X $(CC) -c a.c
- X
- X b.obj: incl.h b.c
- X $(CC) -c b.c
- X
- X The following makefile uses implicit rules to express the same
- X dependencies.
- X
- X pgm.exe: a.obj b.obj
- X $(CC) a.obj b.obj -o $@
- X
- X a.obj b.obj: incl.h
- X
- X This final makefile uses implicit rules to create targets with
- X dependencies in a different directory. Note: this cannot be done
- X with standard Unix make.
- X
- X pgm.exe: a.obj b.obj
- X $(CC) a.obj b.obj -o $@
- X
- X a.obj: incl.h ../a.c
- X
- X b.obj: incl.h ../b.c
- X
- XFILES
- X makefile Current version(s) of make description file.
- X Makefile Alternative to makefile, for Unix.
- X default.mk Default file for user-defined targets, macros,
- X and implicit rules.
- X
- XDIAGNOSTICS
- X MAKE returns an exit status of 1 when it halts as a result of an
- X error. Otherwise it returns an exit status of 0.
- X
- X Badly formed macro
- X A macro definition has been encountered which has incorrect
- X syntax. Most likely, the name is missing.
- X
- X cannot open file
- X The makefile indicated in an include directive was not found or
- X was not accessible.
- X
- X Don't know how to make target
- X There is no makefile entry for target, none of MAKE's implicit
- X rules apply, and there is no .DEFAULT: rule.
- X
- X Improper Macro.
- X An error has occurred during macro expansion. The most likely
- X error is a missing closing bracket.
- X
- X Macro too long (limit 100 chars):
- X A macro name is too long for the internal buffer. Try shortening
- X it to 100 characters or less.
- X
- X rules must be after target
- X A makefile syntax error, where a line beginning with a SPACE or
- X TAB has been encountered before a target line.
- X
- X too many options
- X MAKE has run out of allocated space while processing command
- X line options or a target list.
- X
- X Too many rules defined for target
- X A target occurs multiple times, and each time has rules. A
- X target may only have one set of rules.
- X
- X Unexpected end of line seen
- X A target line without a colon has been encountered.
- X
- XAUTHOR
- X Greg Yachuk Informix Software Inc., Menlo Park CA 94025
- X {pyramid,uunet}!infmx!greggy (415) 926-6300
- X
- X Parts of this program are based on the work by Larry Campbell of
- X DEC, Mike Hickey of University of DC, and by Dan Grayson.
- X
- X Some of this documentation is based on text written by Jeffrey
- X Spidle of Iowa State University and by Dan Grayson.
- X
- X Some of the formatting of this documentation follows the example of
- X Sun Microsystems for their UNIX 4.2 Release.
- X
- XBUGS
- X MAKE allows spaces as well as TABs to introduce shell command
- X lines.
- X
- X Target lines cannot use the double colon (::) syntax.
- X
- X Once a dependency is made, MAKE assumes that the dependency file is
- X present for the remainder of the run. If a rule subsequently
- X removes that file and future targets depend on it's existence,
- X unexpected errors may result.
- X
- X Sometimes MAKE gets confused when searching for implicit rules, and
- X uses several rules instead of a single rule. For example, the two
- X rules .c.o and .l.c may be used, rather than the more direct .l.o
- X rule.
- X
- X If a number of command line flags are run together, and contains
- X either `f' or `d', the whole set of flags is dropped from
- X MAKEFLAGS.
- X
- X The following flags are NOT supported:
- X
- X -p Print out the compete set of macro definitions and target
- X descriptions.
- X
- X -P Report dependencies recursively to show the entire dependency
- X hierarchy, without rebuilding any targets.
- X
- X The following special targets are NOT supported:
- X
- X .KEEP_STATE:
- X .MAKE_VERSION:
- X .PRECIOUS:
- X .SCCS_GET:
- END_OF_FILE
- if test 17010 -ne `wc -c <'make.doc'`; then
- echo shar: \"'make.doc'\" unpacked with wrong size!
- fi
- # end of 'make.doc'
- fi
- if test -f 'parse.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'parse.c'\"
- else
- echo shar: Extracting \"'parse.c'\" \(16977 characters\)
- sed "s/^X//" >'parse.c' <<'END_OF_FILE'
- X/*
- X * parse.c
- X *
- X * 88-10-01 v1.0 created by greg yachuk, placed in the public domain
- X * 88-10-06 v1.1 changed prerequisite list handling
- X * 88-11-11 v1.2 fixed some bugs and added environment variables
- X * 89-07-12 v1.3 stop appending shell commands, and flush output
- X * 89-08-01 v1.4 AB lots of new options and code
- X * 89-10-30 v1.5 greggy -f -S -q options, took some changes from v1.4
- X *
- X */
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <string.h>
- X#ifdef MSDOS
- X#include <stdlib.h>
- X#endif
- X
- X#include "make.h"
- X#include "tstring.h"
- X#include "decl.h"
- X
- X/*
- X * parse - read (text) makefile, and parse
- X * - close file before returing
- X *
- X * lines have the following format:
- X * # with or without preceeding spaces/tabs (comment line)
- X * <TAB> commands (shell line)
- X * name = stuff (macro)
- X * name += stuff (macro)
- X * targ [targ...] : [pre-req...] [; shell cmd ] (target line)
- X */
- Xparse(fd)
- XFILE *fd;
- X{
- X char *input;
- X char *ip;
- X char *colonp;
- X char schar;
- X int ntargs, npreqs, nshell;
- X int tmax, pmax, smax;
- X targptr *targs;
- X fileptr *preqs;
- X shellptr *shells;
- X
- X if (fd == NULL)
- X return (0);
- X
- X /* start off with a short list of targets */
- X targs = (targptr *) grow_list(NULL, &tmax);
- X preqs = (fileptr *) grow_list(NULL, &pmax);
- X shells = (shellptr *) grow_list(NULL, &smax);
- X
- X ntargs = npreqs = nshell = 0;
- X
- X /* maximize buffering */
- X setvbuf(fd, NULL, _IOFBF, 2048);
- X
- X while ((input = tgets(fd)) != NULL)
- X {
- X /* punt on comments and blank lines */
- X for (ip = input; isspace(*ip); ++ip);
- X if (*ip == '#' || *ip == '\0')
- X continue;
- X
- X /* process include files */
- X if (!strncmp(ip, "include", 7))
- X {
- X /* skip spaces AFTER "include" */
- X for (ip += 7; isspace(*ip); ++ip);
- X if (!parse(fopen(ip, "r")))
- X terror(1, tstrcat("cannot open ", ip));
- X continue; /* get next input line */
- X }
- X
- X /* display the makefile line ? */
- X if (opts.display)
- X puts(input);
- X
- X /* get rid of comments and preceeding spaces */
- X for (colonp = ip; *colonp && *colonp != '#'; ++colonp)
- X {
- X if (*colonp == '\'' || *colonp == '"')
- X colonp = tstrspan(colonp);
- X }
- X
- X for (--colonp; colonp >= ip && isspace(*colonp); --colonp);
- X
- X /* we *know* that some non-space is on this line, from above */
- X if (colonp >= ip)
- X *++colonp = '\0';
- X
- X /* see if we have a shell command */
- X if (isspace(*input))
- X {
- X if (ntargs == 0)
- X terror(1, "rules must be after target");
- X got_shell:
- X if (nshell == smax)
- X {
- X shells = (shellptr *)
- X grow_list((char **) shells, &smax);
- X }
- X shells[nshell++] = add_shell(ip);
- X continue;
- X }
- X
- X /* not a shell line, so must be a target or a macro */
- X if (ntargs != 0)
- X {
- X /* link previous preq's and shell's */
- X targs[ntargs] = NULL;
- X preqs[npreqs] = NULL;
- X shells[nshell] = NULL;
- X link_targs(targs, preqs, shells);
- X ntargs = npreqs = nshell = 0;
- X }
- X
- X /* don't break out symbols until macro is invoked */
- X if (add_macro(ip, 0))
- X continue;
- X
- X /* okay, we have a target line; break out macro symbols */
- X input = breakout(ip);
- X
- X /* just look for tokens with standard isspace() separators */
- X ip = token(input, NULL, &schar);
- X while (ip)
- X {
- X colonp = strchr(ip, ':');
- X#ifdef MSDOS
- X /* need to allow c:/bin/make.exe as a target */
- X if (colonp && colonp - ip == 1)
- X colonp = strchr(colonp + 1, ':');
- X#endif
- X if (colonp)
- X {
- X /* got a separator */
- X *colonp = '\0';
- X
- X /* if at front of token, target is done */
- X if (colonp == ip)
- X break;
- X }
- X
- X if (ntargs == tmax)
- X targs = (targptr *) grow_list((char **) targs,
- X &tmax);
- X targs[ntargs] = add_target(ip);
- X
- X /* make sure we don't save .INIT as our 1st target */
- X if (first_targ == NULL && *ip != '.')
- X first_targ = targs[ntargs];
- X ++ntargs;
- X
- X if (colonp)
- X break;
- X ip = token(NULL, NULL, &schar);
- X }
- X
- X /* a target line without a colon? naughty, naughty! */
- X if (!colonp)
- X terror(-1, "Unexpected end of line seen");
- X
- X/*
- X * taking care of four possible cases:
- X * 1) object : source
- X * 2) object: source
- X * 3) object :source
- X * 4) object:source
- X */
- X
- X if (colonp && *++colonp)
- X ip = colonp;
- X else
- X ip = token(NULL, NULL, &schar);
- X
- X /* link the pre-req's */
- X while (ip)
- X {
- X if ((colonp = strchr(ip, ';')) != NULL)
- X {
- X ip[strlen(ip)] = schar;
- X *colonp = '\0';
- X }
- X
- X if (*ip)
- X {
- X if (npreqs == pmax)
- X {
- X preqs = (fileptr *)
- X grow_list((char **) preqs,
- X &pmax);
- X }
- X
- X preqs[npreqs++] = add_file(ip);
- X }
- X
- X if (colonp)
- X {
- X ip = colonp + 1;
- X goto got_shell;
- X }
- X
- X ip = token(NULL, NULL, &schar);
- X }
- X
- X /* gotta free the line allocated by breakout() */
- X tfree(input);
- X }
- X
- X /* link up any dangling dependants */
- X if (ntargs != 0)
- X {
- X targs[ntargs] = NULL;
- X preqs[npreqs] = NULL;
- X shells[nshell] = NULL;
- X link_targs(targs, preqs, shells);
- X }
- X
- X /* clean up our mallocs */
- X tfree(targs);
- X tfree(preqs);
- X tfree(shells);
- X
- X fclose(fd);
- X return (1);
- X}
- X
- X
- X/*
- X * link_targs - force a list of targs to point to same preq's and shell's
- X */
- Xlink_targs(targs, preqs, shells)
- XREGISTER targptr *targs;
- Xfileptr *preqs;
- Xshellptr *shells;
- X{
- X while (targs && *targs)
- X {
- X /* process some special targets */
- X if ((*targs)->tfile->fname[0] == '.')
- X {
- X if (equal((*targs)->tfile->fname, ".SILENT"))
- X opts.silent = 1;
- X else if (equal((*targs)->tfile->fname, ".IGNORE"))
- X opts.ignore = 1;
- X else if (equal((*targs)->tfile->fname, ".SUFFIXES"))
- X /*
- X * set `suffix_targ' to speed up
- X * `default_rule'
- X */
- X suffix_targ = *targs;
- X
- X /* special rule has preq's reset */
- X /* normally, preq's are merely appended */
- X if (*preqs == NULL && (*targs)->tpreq != NULL)
- X {
- X tfree((*targs)->tpreq);
- X (*targs)->tpreq = NULL;
- X }
- X
- X /* special rules have their shell commands replaced */
- X if ((*targs)->tshell != NULL && *shells != NULL)
- X {
- X shellptr *sp;
- X
- X for (sp = (*targs)->tshell; *sp; ++sp)
- X tfree(*sp);
- X tfree((*targs)->tshell);
- X (*targs)->tshell = NULL;
- X }
- X }
- X
- X /* each target in the list points to the preq's and shell's */
- X (*targs)->tpreq = append_preq((*targs)->tpreq, preqs);
- X
- X /* we cannot expand the list of shell commands */
- X if ((*targs)->tshell != NULL && *shells != NULL)
- X {
- X terror(1, tstrcat("Too many rules defined for target ",
- X (*targs)->tfile->fname));
- X }
- X (*targs)->tshell = append_shell((*targs)->tshell, shells);
- X ++targs;
- X }
- X}
- X
- X
- X/* macros must have the format: WORD = more stuff
- X * WORD= more stuff
- X * WORD =more stuff
- X * WORD=more stuff
- X * or: WORD += more stuff
- X * WORD +=more stuff
- X *
- X * it is assumed that there is no leading whitespace in `input'
- X */
- Xadd_macro(input, scmd)
- Xchar *input;
- Xint scmd;
- X{
- X REGISTER char *eqsign;
- X REGISTER char *value;
- X symptr symp;
- X
- X /* gotta have an '=' to be a macro */
- X eqsign = strchr(input, '=');
- X if (eqsign == NULL)
- X return (0);
- X
- X /* make sure we catch imbedded '='s (e.g. MACRO=STUFF) */
- X for (value = input; *value && !isspace(*value); ++value);
- X if (value > eqsign)
- X value = eqsign;
- X
- X /* terminate the macro name */
- X *value = '\0';
- X
- X /* find start of value */
- X for (value = eqsign + 1; isspace(*value); ++value);
- X
- X /* look for concat character */
- X --eqsign;
- X
- X if (eqsign < input || (eqsign == input && *eqsign == '+'))
- X terror(1, "Badly formed macro");
- X
- X if (*eqsign == '+')
- X {
- X /* append to the current macro definition */
- X *eqsign = '\0';
- X symp = get_symbol(input, scmd);
- X if (symp->scmd && !scmd)
- X return (1);
- X if (symp->slevel < make_level)
- X symp = dup_symbol(symp, symp->svalue);
- X if (symp->svalue)
- X {
- X eqsign = tstrcat(symp->svalue, " ");
- X value = tstrcat(eqsign, value);
- X tfree(eqsign);
- X tfree(symp->svalue);
- X symp->svalue = value;
- X return (1);
- X }
- X }
- X
- X add_symbol(input, value, scmd);
- X return (1);
- X}
- X
- X
- X/*
- X * add_symbol - add a <name,value> pair to the symbol table
- X * - override existing symbol value
- X * - mark as either command-line macro or not
- X */
- Xadd_symbol(name, value, scmd)
- Xchar *name;
- Xchar *value;
- Xint scmd;
- X{
- X REGISTER symptr symp;
- X
- X symp = get_symbol(name, scmd);
- X if (symp->scmd & !scmd)
- X return;
- X if (symp->slevel < make_level)
- X symp = dup_symbol(symp, NULL); /* don't dup the value */
- X if (symp->svalue)
- X tfree(symp->svalue);
- X symp->svalue = tstrcpy(value);
- X symp->scmd = scmd;
- X}
- X
- X
- X/*
- X * get_symbol - find a symbol in the symbol table
- X * - if non-extant, create <name,NULL>
- X * - return created or found symbol node
- X */
- Xsymptr
- Xget_symbol(name, scmd)
- Xchar *name;
- Xint scmd;
- X{
- X REGISTER symptr symp;
- X REGISTER t_mask mask;
- X char *np;
- X
- X /* use `mask' to screen out most string comparisons */
- X mask = 0;
- X np = name;
- X while (*np)
- X mask += *np++;
- X
- X /* linear search through symbol list */
- X for (symp = symbol_list; symp != NULL; symp = symp->snext)
- X {
- X if (mask != symp->smask)
- X continue;
- X
- X if (equal(name, symp->sname))
- X return (symp);
- X }
- X
- X symp = tnew(symnode); /* allocate symbol node */
- X symp->smask = mask; /* record mask for later */
- X symp->sname = tstrcpy(name); /* allocate string and copy name */
- X symp->scmd = scmd; /* command line macro? */
- X symp->slevel = make_level; /* current new_make() level */
- X
- X /* get the value from the environment, if it is there */
- X
- X if ((symp->svalue = getenv(name)) != NULL)
- X {
- X symp->svalue = tstrcpy(symp->svalue);
- X
- X /*
- X * if `-e', let command line macros override, but not macro
- X * assignments in the makefile.
- X */
- X if (opts.envirn)
- X symp->scmd = 1;
- X }
- X
- X symp->snext = symbol_list; /* link to head of symbol list */
- X symbol_list = symp;
- X
- X return (symp);
- X}
- X
- X
- X/*
- X * dup_sym - duplicate a symbol node, but at current new_make() level
- X */
- Xsymptr
- Xdup_symbol(sp, svalue)
- Xsymptr sp;
- Xchar *svalue;
- X{
- X symptr nsp;
- X
- X nsp = tnew(symnode); /* allocate symbol node */
- X nsp->smask = sp->smask; /* record mask for later */
- X nsp->sname = tstrcpy(sp->sname); /* allocate string and copy
- X * name */
- X nsp->svalue = (svalue == NULL) ? NULL : tstrcpy(svalue);
- X nsp->scmd = sp->scmd; /* command line macro? */
- X nsp->slevel = make_level; /* current new_make() level */
- X
- X nsp->snext = symbol_list; /* link to head of symbol list */
- X symbol_list = nsp;
- X
- X return (nsp);
- X}
- X
- X
- X/*
- X * add_target - return extant target node, or create new one
- X */
- Xtargptr
- Xadd_target(name)
- Xchar *name;
- X{
- X t_mask mask;
- X REGISTER targptr targp;
- X fileptr filep;
- X
- X /* each target must have a file node */
- X filep = add_file(name);
- X
- X /* see if target already exists */
- X targp = hash_target(name, &mask);
- X if (targp)
- X return (targp);
- X
- X /* oh well, gotta create one */
- X targp = tnew(targnode); /* allocate a target node */
- X targp->tmask = mask; /* save mask for later */
- X targp->tfile = filep; /* save pointer to file node */
- X targp->tpreq = NULL; /* no pre-req's yet */
- X targp->tshell = NULL; /* no shell lines yet */
- X
- X targp->tnext = target_list; /* link to front of target list */
- X target_list = targp;
- X
- X return (targp);
- X}
- X
- X
- X/*
- X * hash_target - look up target (by name) in target list
- X * - return target node or NULL
- X * - if requested, also return the mask
- X */
- Xtargptr
- Xhash_target(name, maskp)
- Xchar *name;
- Xt_mask *maskp;
- X{
- X REGISTER targptr targp;
- X REGISTER t_mask mask;
- X char *np;
- X
- X /* use `mask' to screen out most string comparisons */
- X mask = 0;
- X np = name;
- X while (*np)
- X mask += *np++;
- X
- X /* see if we gotta return it */
- X if (maskp != NULL)
- X *maskp = mask;
- X
- X /* linear search through target list */
- X for (targp = target_list; targp != NULL; targp = targp->tnext)
- X {
- X if (mask != targp->tmask)
- X continue;
- X
- X /* target name is ONLY stored in the file node */
- X if (equal(name, targp->tfile->fname))
- X return (targp);
- X }
- X
- X /* nope, no target here */
- X return (NULL);
- X}
- X
- X
- X/*
- X * add_file - return a found or created file node
- X */
- Xfileptr
- Xadd_file(name)
- Xchar *name;
- X{
- X t_mask mask;
- X REGISTER fileptr filep;
- X
- X /* see if file node already exists */
- X filep = hash_file(name, &mask);
- X if (filep)
- X return (filep);
- X
- X filep = tnew(filenode); /* allocate new file node */
- X filep->fmask = mask; /* save mask for later */
- X filep->fname = tstrcpy(name); /* allocate string and copy name */
- X filep->ftime = MAXNEGTIME; /* init MODIFY time to long time ago */
- X
- X filep->fnext = file_list; /* link to head of file list */
- X file_list = filep;
- X
- X return (filep);
- X}
- X
- X
- X/*
- X * hash_file - look up file (by name) in file list
- X * - return file node or NULL
- X * - if requested, also return the mask
- X */
- Xfileptr
- Xhash_file(name, maskp)
- Xchar *name;
- Xt_mask *maskp;
- X{
- X REGISTER fileptr filep;
- X REGISTER t_mask mask;
- X char *np;
- X
- X /* use `mask' to screen out most string comparisons */
- X mask = 0;
- X np = name;
- X while (*np)
- X mask += *np++;
- X
- X /* see if we gotta return it */
- X if (maskp != NULL)
- X *maskp = mask;
- X
- X /* linear search through file list */
- X for (filep = file_list; filep != NULL; filep = filep->fnext)
- X {
- X if (filep->fmask != mask)
- X continue;
- X
- X if (equal(filep->fname, name))
- X return (filep);
- X }
- X
- X /* nope, no file here */
- X return (NULL);
- X}
- X
- X
- X/*
- X * append_node - add a node to the end of an array of nodes
- X */
- Xchar **
- Xappend_node(node, adds, size)
- Xchar **node;
- Xchar **adds;
- Xint size;
- X{
- X REGISTER int addlen, len;
- X
- X for (addlen = 0; adds[addlen] != NULL; ++addlen);
- X if (addlen++ == 0)
- X return (node);
- X
- X len = 0;
- X
- X if (node != NULL)
- X {
- X for (; node[len] != NULL; ++len);
- X node = (char **) trealloc((char *) node, (len + addlen) * size);
- X }
- X else
- X node = (char **) talloc(addlen * size);
- X
- X memcpy(node + len, adds, addlen * size);
- X return (node);
- X}
- X
- X/*
- X * add_shell - create a new shell node, and add to end of given list
- X */
- Xshellptr
- Xadd_shell(input)
- Xchar *input;
- X{
- X REGISTER shellptr snode;
- X
- X snode = tnew(shellnode);/* allocate a new shell node */
- X snode->s_shell = snode->s_ignore = snode->s_silent = 0;
- X
- X for (; isspace(*input); ++input); /* skip over leading spaces */
- X for (;; ++input)
- X {
- X if (*input == '+')
- X snode->s_shell = 1; /* must use command.com */
- X else if (*input == '-')
- X snode->s_ignore = 1; /* ignore return value */
- X else if (*input == '@')
- X snode->s_silent = 1; /* don't echo command */
- X else
- X break;
- X }
- X
- X snode->scmd = tstrcpy(input); /* allocate string and copy command */
- X
- X snode->slink = shell_list; /* attach to global list */
- X shell_list = snode;
- X
- X return (snode);
- X}
- X
- X
- X/*
- X * breakout - replace macro names with values
- X * - apply recursively
- X * note: allocates (and returns) a string which must be freed
- X */
- Xchar *
- Xbreakout(input)
- XREGISTER char *input;
- X{
- X char *dest, *dend;
- X REGISTER char *dp;
- X int dlen;
- X int tlen;
- X int state;
- X char symname[100];
- X char *sp;
- X symptr symp;
- X int slen;
- X char endch;
- X
- X /* allocate a string twice as long as input string */
- X
- X dlen = strlen(input) * 2;
- X dest = dp = talloc(dlen);
- X dend = dest + dlen;
- X
- X/*
- X * state machine with 4 states
- X * 0) normal text -- just copy
- X * 1) starting macro -- define end char (e.g. ')', '}')
- X * 2) macro name -- copy to a buffer
- X * 3) end of macro -- look up value, and copy
- X */
- X state = 0;
- X
- X while (*input || state == 3)
- X {
- X /* if we don't have enough room, double size of string */
- X if (dp == dend)
- X {
- X dlen *= 2;
- X tlen = dp - dest;
- X dest = trealloc(dest, dlen);
- X dp = dest + tlen;
- X dend = dest + dlen;
- X }
- X
- X switch (state)
- X {
- X case 0:
- X if (*input == '$')
- X state = 1; /* found a macro */
- X else
- X *dp++ = *input++;
- X break;
- X
- X case 1:
- X state = 2; /* only in this state for 1 char */
- X sp = symname;
- X switch (*++input)
- X {
- X case '(':
- X endch = ')';
- X break;
- X case '{':
- X endch = '}';
- X break;
- X default:
- X /* single char; go to state 3 immediately */
- X *sp++ = *input;
- X state = 3;
- X break;
- X }
- X ++input;/* skip bracket (or character) */
- X break;
- X
- X case 2:
- X if (*input == endch)
- X state = 3;
- X else
- X *sp++ = *input;
- X
- X if ((sp - symname) >= (sizeof symname / sizeof symname[0]))
- X {
- X sp[-1] = '\0';
- X terror(1,
- X tstrcat("Macro too long (limit 100 chars): ",
- X symname));
- X }
- X
- X ++input;/* make sure we skip end char */
- X break;
- X
- X case 3:
- X *sp = '\0';
- X symp = get_symbol(symname, 0);
- X sp = symp->svalue;
- X slen = -1;
- X while (sp && *sp)
- X {
- X /*
- X * if value has a macro in it, we must
- X * process recursively
- X */
- X if (*sp == '$')
- X {
- X sp = breakout(symp->svalue);
- X /* now guaranteed not to have a '$' */
- X slen = strlen(sp);
- X break;
- X }
- X ++sp;
- X }
- X
- X if (slen == -1)
- X {
- X /* value did NOT have a macro */
- X slen = (sp - symp->svalue);
- X sp = symp->svalue;
- X }
- X
- X /* if we have not enough room, expand */
- X if (slen >= (dend - dp))
- X {
- X /* use slen to make sure that we can fit */
- X dlen = dlen * 2 + slen;
- X tlen = dp - dest;
- X dest = trealloc(dest, dlen);
- X dp = dest + tlen;
- X dend = dest + dlen;
- X }
- X
- X /* if length is zero, don't bother to copy */
- X if (slen)
- X {
- X strcpy(dp, sp);
- X dp += slen;
- X }
- X
- X if (sp != symp->svalue)
- X tfree(sp); /* must've called `breakout' */
- X
- X state = 0; /* and we are back to text */
- X break;
- X }
- X }
- X
- X if (state != 0)
- X terror(1, tstrcat("Improper macro.\n", dest));
- X
- X *dp = '\0'; /* terminate the string */
- X return (dest); /* and return it */
- X}
- END_OF_FILE
- if test 16977 -ne `wc -c <'parse.c'`; then
- echo shar: \"'parse.c'\" unpacked with wrong size!
- fi
- # end of 'parse.c'
- fi
- echo shar: End of archive 2 \(of 3\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-